--[[
-- @Author:			
-- @DateTime:	2020-10-30 23:05:48
-- @Description: 客户端消息的封包与解包
	
	消息包= head(12) + msg_id(2) + msg_data_size(2) + msg_data

--]]



local proto = require("proto")
local Netpack = require("skynet.netpack")
local WsNetpack = require("websocketnetpack")
local Socket = require("skynet.socket")



--消息打包类
local ClientPack = class("ClientPack")


function ClientPack:ctor()
	self.head_size = 12 --head的大小
	self.version = 1	--消息版本
	self.proto_type = 1 --1=protobuff 2=json
	self.check_code = 1 --校验码
	self.ext = 0 --预留

   	self.pbLoader = new("pbLoader")
    self.pbLoader:load()

end

-- 设置网络消息协议头
function ClientPack:setHeader()
	--size = [1,1,4,3] 头大小,协议版本号,协议类型,数据校验码
	local str = ""
	str = str .. string.pack(">H", self.head_size) --2
	str = str .. string.pack(">B", self.version) 	--1
	str = str .. string.pack(">B", self.proto_type)	--1
	str = str .. string.pack(">I4", self.check_code) --4
	str = str .. string.pack(">I4", self.ext)	     --4
	return str
end

--获取网络消息协议头
function ClientPack:getHeader(message)
	if string.len(message) < self.head_size then 
		print("############ MessagePack:getHeader invalid message_size " .. string.len(message))
		return 
	end
	return {        
		head_size 	= string.unpack(">H", message:sub(1,2)),
		version 	= string.unpack(">B", message:sub(3,3)),
		proto_type 	= string.unpack(">B", message:sub(4,4)),
		check_code 	= string.unpack(">I4", message:sub(5,8)),
		ext 		= string.unpack(">H", message:sub(9,12)),
	}
end

--打包网络消息
function ClientPack:pack(msg_name, msg_body)
	local msg_id = proto[msg_name]
	if not msg_id then 
		g.Log():error("____ClientPack:pack error msg_id is nil", msg_name)
		return 
	end
	local msg_id = "" .. string.pack(">H", msg_id) 
	local msg_data = self.pbLoader:encode(msg_name, msg_body)
	local msg_data_size = "" .. string.pack(">H", #(msg_data)) 
	local pack_data = self:setHeader() .. msg_id ..msg_data_size.. msg_data
	return pack_data
end

--解包网络消息
function ClientPack:unpack(message_buf, message_size)
	if not message_size then
		message_size = #message_buf 
	end
	if message_size < self.head_size then
		--长度不足一个包头
		g.Log():error("############ unpack invalid message_size ".. message_size)
		return 
	end
	local message = ""
	if type(message_buf) == 'string' then 
		message = message_buf
	else
		message = skynet.tostring(message_buf, message_size)  
	end	
	local header = self:getHeader(message)
	--消息头的校验
	if not header or header.head_size ~= self.head_size then 
		g.Log():error("############ unpack invalid header ", header)
		return 
	end
	local msg_id =  string.unpack(">H", message:sub(self.head_size + 1, self.head_size + 2))
	msg_id = tonumber(msg_id)
	local msg_name = proto[msg_id]
	local msg_data_size = string.unpack(">H",message:sub(self.head_size + 3, self.head_size + 4))
	msg_data_size = tonumber(msg_data_size)
	-- print("__2__msg_data_size",msg_data_size)
	local proto_data = message:sub(self.head_size + 5, self.head_size + 5 + msg_data_size-1)
	local msg_data = self.pbLoader:decode(msg_name, proto_data)	
	-- g.Log():debug("____11111111___msg_data__",  msg_id, msg_name, msg_data)
	if not msg_data then 
		return
	end
	g.Log():debug("____ClientPack:unpack_____",  msg_id, msg_name, msg_data)
	return msg_id, msg_name, msg_data
end

--写入socket
--conn_type: 放着的方式 websocket or socket
function ClientPack:send(fd, msg_name, msg_body, conn_type)
	local msg = self:pack(msg_name, msg_body)
	if not msg then 

		return 
	end
	local msg_tmp, sz
	if conn_type and conn_type == "websocket" then
		msg_tmp, sz = WsNetpack.pack(msg)
	else
		msg_tmp, sz = Netpack.pack(msg)
	end
	if not msg_tmp or not sz then 
		g.Log():error('send error msg_tmp=nil or sz=nil')
		return false
	end
	local ok, err = xpcall(Socket.write, debug.traceback, fd, msg_tmp, sz)
	if not ok then
		g.Log():error('send faild:', err)
		return false
	end
	return true
end










---------------------------------------------------------
--测试
---------------------------------------------------------
function ClientPack:test( ... )
    local NoticeInfo = {
        id = 1,
        infotype = 2,
        gameid = 3,
        content = "ssssssssssss",
    }
    local data = self:pack("user.NoticeInfo", NoticeInfo)	
    unpack_data = self:unpack(data)	
    g.Log():error("_____unpack_data", unpack_data)
end


return ClientPack